package com.shigen.demo.excel.listener;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.shigen.demo.entity.User;
import com.shigen.demo.excel.vo.UserVo;
import com.shigen.demo.service.UserService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;

/**
 * 事件监听
 *
 * @author shigenfu
 * @date 2023/8/20 11:14 下午
 */
@RequiredArgsConstructor
public class EasyExcelGeneralDataListener extends AnalysisEventListener<UserVo> {

    private UserService userService;
    /**
     * 批量保存的数据行数
     */
    private static final Integer BATCH_SIZE = 5;
    /**
     * 单次导入最大的数据量
     */
    private static final Integer MAX_SIZE = 10000;
    /**
     * 电话验证正则
     */
    private static final Pattern PHONE_REGEX = Pattern.compile("^1[0-9]{10}$");
    /**
     * 错误信息
     */
    private final List<String> errorMsgList = new ArrayList<>();
    /**
     * 用于存储读取的数据
     */
    private final List<UserVo> dataList = new ArrayList<>();

    public EasyExcelGeneralDataListener(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        int totalRows = context.readRowHolder().getRowIndex() + 1;
        if (totalRows > MAX_SIZE) {
            errorMsgList.add("数据量过大，最多导入 " + MAX_SIZE + " 条数据");
            throw new RuntimeException("数据量过大，最多导入 " + MAX_SIZE + " 条数据");
        }
    }

    @Override
    public void invoke(UserVo user, AnalysisContext context) {
        Integer rowIndex = context.readRowHolder().getRowIndex();
        // 数据验证add进入集合
        if (dataChecked(rowIndex, user)) {
            dataList.add(user);
        }
        // size是否为200000条:这里其实就是分批.当数据等于20w的时候执行一次插入
        if (dataList.size() >= BATCH_SIZE) {
            // 存入数据库:数据小于1w条使用Mybatis的批量插入即可
            saveData();
            // 清理集合便于GC回收
            dataList.clear();
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof RuntimeException) {
            throw exception;
        }
        int rowIndex = context.readRowHolder().getRowIndex() + 1;
        errorMsgList.add("第" + rowIndex + "行数据异常，请检查后重新导入");
    }

    private boolean dataChecked(Integer rowIndex, UserVo user) {
        return usernameValid(rowIndex, user.getUsername()) && phoneValid(rowIndex, user.getPhone());
    }

    public List<String> getErrorMsgList() {
        return errorMsgList;
    }

    /**
     * 保存数据到DB
     */
    private void saveData() {
        userService.importDBFromExcel10w(dataList);
        dataList.clear();
    }

    /**
     * Excel中所有数据解析完毕会调用此方法
     *
     * @param context 上下文
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 保存最后的数据
        saveData();
        dataList.clear();
    }


    private boolean usernameValid(Integer rowIndex, String username) {
        if (StrUtil.isEmpty(username)) {
            errorMsgList.add("第" + rowIndex + "行'用户名'为空");
            return false;
        }
        return true;
    }

    private boolean phoneValid(Integer rowIndex, String phone) {
        // 根据正则校验
        if (!ReUtil.isMatch(PHONE_REGEX, phone)) {
            errorMsgList.add("第" + rowIndex + "行'手机号'格式错误");
            return false;
        }
        return true;
    }

}
